package environment;

import java.awt.Point;
import java.util.ArrayList;

import data.Logger;

/**
 * Class to represent the sonars of the robot
 * Main methods: getSonarValues and isObstacleDetected
 * TODO Currently using too many points, need to maintain only a few
 * @author Toar
 */
public class Sonar {
	
	private Line s1,s2,s3;
	protected boolean s1Fire, s2Fire, s3Fire;
	private String ownerID;
	private Robot myRobot;
	
	public enum Loc{
		LEFT, RIGHT, CENTER, RIGHTANDCENTER, LEFTANDCENTER, RIGHTANDLEFT, ALL, NONE 
	}
	
	public Sonar(Robot owner)
	{
		this.ownerID = owner.getID();
		this.myRobot = owner;
	}
	
	public Sonar(Point p0, Point p1, Point p2, Point p5, Point p6, Point p7,int length, String ID)
	{
		this.s1 = new Line(p5, p0); //center
		this.s2 = new Line(p6, p2); //right
		this.s3 = new Line(p7, p1); // left
		this.ownerID = ID;
	}
	
	/**
	 * Checks whether or not any of the sonars detected an obstacle
	 * @param a
	 * @return
	 */
	public boolean isObstacleDetected(ArrayList<EnvObjInterface> a)
	{
		if(lineOutside())
			return true;
		for(EnvObjInterface obj : a)
		{
			if(obj.getID() != ownerID &&
					(this.s1.intersects(obj.getBounds()) || /** if any of the sonar detects **/
					this.s2.intersects(obj.getBounds()) ||
					this.s3.intersects(obj.getBounds()) 
					)
			  )	
			{
				if(!obj.isPushable())
				{
					if(obj.getID().startsWith("o") || obj.getID().startsWith("r")) return true;
					System.out.println(ownerID + " AVOID " + obj.getID() + " NOT PUSHABLE ");
					//Logger.log(ownerID + " AVOID " + obj.getID());
					return true;
				}
				else 
				{
					/** 
					 * Object is pushable, so we know it's a box
					 * Therefore, if it's currently being pushed, other robots will treat 
					 * it as an obstacle and get out of the way 
					 **/
					Box b = (Box) obj;
					if(b.isBeingPushed) 
					{
						//System.out.println(ownerID + " AVOID " + b.getID() + " IS BEING PUSHED ");
						Logger.log(ownerID + " AVOID " + b.getID());
						return true;
					}
				}
			}
		}
		return false;			
	}
	
	/**
	 * 
	 * @param obj
	 * @return
	 */
	public boolean isSingleObstacleDetected(EnvObjInterface obj)
	{
		return this.s1.intersects(obj.getBounds()) || this.s2.intersects(obj.getBounds())||
			this.s3.intersects(obj.getBounds());
	}
	
	/**
	 * Get which sonars are firing
	 * @param a
	 * @return
	 */
	public Loc getSonarValues(ArrayList<EnvObjInterface> a)
	{
		s1Fire = false; s2Fire = false; s3Fire = false;
		/** 
		 * Should check sonar against all objects
		 */
		for(EnvObjInterface obj : a)
		{
			/**
			 * Checks for obstacles detected by the sonars
			 * Non pushable objects are obstacles
			 * Pushable objects are boxes
			 * Boxes that are being pushed, or boxes in the ignore list
			 * will be considered obstacles
			 */
			if(obj.getID() != ownerID &&
					(!obj.isPushable() ||
					((Box)obj).isBeingPushed ||
					( myRobot.ignoreBoxes.contains(obj.getID()))
					)
			  )
			{
				
				if((this.s1.intersects(obj.getBounds())  || ScreenConstants.isOutOfScreen(s1.p1)))
					s1Fire = true;
				if((this.s2.intersects(obj.getBounds())  || ScreenConstants.isOutOfScreen(s2.p1)))
					s2Fire = true;
				if((this.s3.intersects(obj.getBounds())  || ScreenConstants.isOutOfScreen(s3.p1)))
					s3Fire = true;
			}		
		}
		if(s1Fire && s2Fire && s3Fire)
			return Loc.ALL;
		else if(s1Fire && s2Fire)
			return Loc.RIGHTANDCENTER;
		else if(s1Fire && s3Fire)
			return Loc.LEFTANDCENTER;
		else if(s2Fire && s3Fire)
			return Loc.RIGHTANDLEFT;
		else if(s1Fire)
			return Loc.CENTER;
		else if(s2Fire)
			return Loc.RIGHT;
		else if(s3Fire)
			return Loc.LEFT;
		else
			return Loc.NONE;
	}	
	
	/**
	 * Update sonar points
	 * @param p0
	 * @param p1
	 * @param p2
	 * @param p5
	 * @param p6
	 * @param p7
	 */
	public void updatePoints(Point p0, Point p1, Point p2, Point p5, Point p6, Point p7)
	{
		this.s1 = new Line(p5, p0); //center
		this.s2 = new Line(p6, p2); //right
		this.s3 = new Line(p7, p1); // left
	}
	
	/**
	 * Checks whether sonar lines are outside the border
	 * @return
	 */
	private boolean lineOutside()
	{
		return (ScreenConstants.isOutOfScreen(s1.p1) ||	
				ScreenConstants.isOutOfScreen(s2.p1) ||	
				ScreenConstants.isOutOfScreen(s3.p1));
	}
}
